;(function() {
	var expand = window.expand = window.expand || {};

    var Observable = (function(){
        var listen, log, obj, one, remove, trigger, that;
        obj = {};
        that = this;
        listen = function(key, eventfn){
            var stack, _ref;
            stack = (_ref = obj[key]) != null ? _ref : obj[key] = [];
            return stack.push(eventfn);
        };
        one = function(key, eventfn){
            remove(key);
            return listen(key, eventfn);
        };
        remove = function(key){
            var _ref;
            return (_ref = obj[key]) != null ? _ref.length = 0 : void 0;
        };
        trigger = function(){
            var fn, stack, _i, _len, _ref, key;
            key = Array.prototype.shift.call(arguments);
            stack = (_ref = obj[key]) != null ? _ref : obj[key] = [];
            for (_i = 0, _len = stack.length; _i < _len; _i++) {
                fn = stack[_i];
                if (fn.apply(that, arguments) === false) {
                    return false;
                }
            }
        }
        return {
            listen: listen,
            one: one,
            remove: remove,
            trigger: trigger
        }
    })();
    
	var slider = function(container, options){
		if (!container) return;
		
        var options = options || {},
            currentIndex = 0,
            cls = options.activeControllerCls,
            delay = options.delay,
            direction = options.direction,
            rev_direction,
            isAuto = options.auto,
            controller = options.controller,
            event = options.event,
            interval,
            slidesWrapper = container.children().first(),
            slides = slidesWrapper.children(),
            length = slides.length,
            childWidth = container.width(),
            totalWidth = childWidth * slides.length;
			
        if(direction =="right"){
            rev_direction = "left"
        }else if(direction =="up"){
            rev_direction = "down"
        }else if(direction =="down"){
            rev_direction = "up"
        }else{
            direction = "left";
            rev_direction = "right"
        }
		
		function init() {
            mode();
            isAuto && autoPlay();
            slides.mouseover(function(){
                stop();
            }).mouseout(function(){
                isAuto && autoPlay();
            });
			controller && bindControl();
        }

		function bindControl(){
			var controlItem = controller.children();
			event == 'hover' ? controlItem.mouseover(function(){
                stop();
                var index = $(this).index();
                if (index < currentIndex) {
                    play(index, options.mode, rev_direction, direction);
                }
                else {
                    play(index, options.mode, direction, rev_direction);
                }
            }).mouseout(function(){
                isAuto && autoPlay();
            }) : controlItem.click(function(){
                stop();
                var index = $(this).index();
                
                if (index < currentIndex) {
                    play(index, options.mode, rev_direction, direction);
                }
                else {
                    play(index, options.mode, direction, rev_direction);
                }
                isAuto && autoPlay();
            });
		}
        
        function mode() {
            var wrapper = container.children().first();

           wrapper.children().css({
                'position': 'absolute',
                'left': 0,
                'top': 0
            }).first().siblings().hide();
        }

        function autoPlay() {
            interval = setInterval(function () {
                triggerPlay(currentIndex);
            }, options.time);
        }

        function triggerPlay(cIndex,rollback) {
            var index;

            (cIndex == length - 1) ? index = 0 : index = cIndex + 1;
            if(rollback){
                play(index, options.mode ,rev_direction, direction);
            }else{
                play(index, options.mode ,direction, rev_direction);
            }
        }

        function play(index, mode ,direction, rev_direction) {
            slidesWrapper.stop(true, true);
            slides.stop(true, true);
            mode == 'slide' ? (function () {
                if (slidesWrapper.children(':visible').index() == index) return;
                slidesWrapper.children().hide("slide",{ direction: direction},delay).eq(index).show("slide",{ direction: rev_direction},delay);
            })() : (function () {
                if (slidesWrapper.children(':visible').index() == index) return;
                slidesWrapper.children().fadeOut(delay).eq(index).fadeIn(delay);
            })();

            try {
                controller.children('.' + cls).removeClass(cls);
                controller.children().eq(index).addClass(cls);
            } catch (e) { }

            currentIndex = index;
			//这里使用观察者通知，不管有没人监听
			expand.Observable.trigger("slider",{index:currentIndex});
        }

        function stop() {
            clearInterval(interval);
        }

        function prev() {
            stop();
            currentIndex == 0 ? triggerPlay(length - 2,true) : triggerPlay(currentIndex - 2,true);
            isAuto && autoPlay();
        }

        function next() {
            stop();
            currentIndex == length - 1 ? triggerPlay(-1) : triggerPlay(currentIndex);
            isAuto && autoPlay();
        }

        init();

        // expose the Slider API
        return {
            prev: function () {
                prev();
            },
            next: function () {
                next();
            }
        }
	};
	
    var showToast = function(msg){
    	var wrap = $("div.expand-toast");
    	if(wrap.length <= 0){
    		wrap = $('<div class="expand-toast" flag=0><span></span></div>').appendTo($("body"));
    	}
    	if(wrap.attr("flag") == true)return;
    	
    	wrap.attr("flag",1);
    	$("span",wrap).text(msg);
    	
    	wrap.animate({display:"block",opacity:1},200,"ease-in");
    	
    	var h = setInterval(function(){
    		wrap.animate({opacity:0},200,"ease-in",function(){wrap.hide();wrap.attr("flag",0);});
    		clearInterval(h);
    	},2000);
    };
    
    var mask = function(){
    	var mask;
    	return function(){
    		return mask || (mask = $('<div id="expand-mask"></div>').appendTo("body"));
    	}
    }();
    
    var lazyImg = function(){
    	var defObj,pageTop,settings = {
			defObj: "#lazyLoad-box",
			defHeight: 0
		};
    	
    	var reg = function(options){
    		var that = this;
    		settings = $.extend(settings, options || {});
    		that.defObj = "object" == typeof settings.defObj ? settings.defObj : $(settings.defObj), that.pageTop = function(){
        		var d = document, y = Math.max(d.documentElement.scrollTop, d.body.scrollTop);
        		return d.documentElement.clientHeight + y + settings.defHeight;
        	};
        	
        	$(window).bind("scroll", function(){
        		that.imgLoad();
        	}), $(window).bind("resize", function(){
        		that.imgLoad();
        	});
        	return this;
    	}
    	
    	var rechangeSrc = function(obj){
    		var src = obj && obj.attr("data-src");
			if(src === undefined || src === "")return;
		    if(src){
		    	obj.css({opacity: "0.3"}).attr("src", src).removeAttr("data-src").animate({opacity: "1"});
		    }
    	}
    	
    	var imgLoad = function(){
    		var that = this;
    		this.defObj.find("img").each(function(){
    			$(this).offset().top <= that.pageTop() && that.rechangeSrc($(this));
    		})
    	}
    	
    	return {
    		reg:reg,
    		rechangeSrc:rechangeSrc,
    		imgLoad:imgLoad
    	}
    }();
    
    var ajax = function (options){
		var setting = {
			dataType:"json",
			type:"GET",
			beforeSend:function(){
				options.beforeSend && $.isFunction(options.beforeSend) && options.beforeSend();
			},error:function(res){
				// Callback that is executed the the server drops error
				options.error && $.isFunction(options.error) && options.error(res);
			},complete:function(){
				// Callback that is executed on request complete (both: error and success)
				options.complete && $.isFunction(options.complete) && options.complete();
			}
		};
		var arg = $.extend(setting,options);
		arg.success = function(res){
			if(res.result==="errors"){
				expand.ui.showToast(res.errors);
			}else{
				// Callback that is executed if the request succeeds
				options.success && $.isFunction(options.success) && options.success(res);
			}
		}
		return $.ajax(arg);
	};
	
    var getJSON = function(options){
    	$.extend(options,{
    		dataType:"json"
    	});
    	return expand.ajax(options);
    };
    
    var post = function(options){
    	$.extend(options,{
    		type:"POST"
    	});
    	return expand.ajax(options);
    };
    
    var get = function(options){
    	$.extend(options,{
    		type:"GET"
    	});
    	return expand.ajax(options);
    };
	
	$.extend(expand,{
		ui:{
			slider:slider,
			showToast:showToast,
			mask:mask,
			lazyImg:lazyImg
		},
		Observable:Observable,
		ajax:ajax,
		getJSON:getJSON,
		post:post,
		get:get
	});
})();